package com.douqu.game.battle.entity;

import com.alibaba.druid.sql.ast.statement.SQLIfStatement;
import com.douqu.game.battle.controller.BattleController;
import com.douqu.game.core.controller.PlayerController;
import com.douqu.game.core.e.E_BattleAObjectStatus;
import com.douqu.game.core.entity.battle.BattleAObject;
import com.douqu.game.core.entity.battle.BattleSkill;
import com.douqu.game.core.entity.battle.Position;
import com.douqu.game.core.entity.battle.SpriteBattleTmp;
import com.douqu.game.core.entity.common.TwoTuple;
import com.douqu.game.core.controller.SpriteController;
import com.douqu.game.core.entity.sprite.Soldier;
import com.douqu.game.core.entity.sprite.Sprite;
import com.douqu.game.core.factory.ConfigFactory;
import com.douqu.game.core.protobuf.SGMainProto;
import com.douqu.game.core.protobuf.SGWarProto;
import com.douqu.game.core.util.Utils;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Created by bean on 2017/7/25.
 */
public class BattleSoldierAObject extends BattleAObject {

    Logger logger = Logger.getLogger(BattleSoldierAObject.class);

    private Soldier soldier;

    /**
     * 路线列表
     */
    private List<Position> routeList;

    /**
     * 当前走到哪一步
     */
    private int curRouteIndex;


    public BattleSoldierAObject(SpriteController playerController, Soldier soldier, int fc, int uniqueId)
    {
        super(playerController, uniqueId);

        this.objectId = soldier.id;
        this.soldier = soldier;
        this.unitType = soldier.unitType;
        this.teamNo = playerController.getAttachment().getTeamNo();
//        this.atkType = soldier.atkType;
        this.defType = soldier.defType;

        this.hp = maxHp  = getAttribute(soldier.hp,          ConfigFactory.ATTRIBUTE_HP,           ConfigFactory.ATTRIBUTE_HP_PLUS);
        this.physicsAtk  = getAttribute(soldier.physicsAtk,  ConfigFactory.ATTRIBUTE_PHYSICS_ATK,  ConfigFactory.ATTRIBUTE_PHYSICS_ATK_PLUS);
        this.punctureAtk = getAttribute(soldier.punctureAtk, ConfigFactory.ATTRIBUTE_PUNCTURE_ATK, ConfigFactory.ATTRIBUTE_PUNCTURE_ATK_PLUS);
        this.magicAtk    = getAttribute(soldier.magicAtk,    ConfigFactory.ATTRIBUTE_MAGIC_ATK,    ConfigFactory.ATTRIBUTE_MAGIC_ATK_PLUS);
        this.physicsDef  = getAttribute(soldier.physicsDef,  ConfigFactory.ATTRIBUTE_PHYSICS_DEF,  ConfigFactory.ATTRIBUTE_PHYSICS_DEF_PLUS);
        this.punctureDef = getAttribute(soldier.punctureDef, ConfigFactory.ATTRIBUTE_PUNCTURE_DEF, ConfigFactory.ATTRIBUTE_PUNCTURE_DEF_PLUS);
        this.magicDef    = getAttribute(soldier.magicDef,    ConfigFactory.ATTRIBUTE_MAGIC_DEF,    ConfigFactory.ATTRIBUTE_MAGIC_DEF_PLUS);
//        this.power       = getAttribute(soldier.power, ConfigFactory.ATTRIBUTE_MAGIC_DEF, ConfigFactory.ATTRIBUTE_MAGIC_DEF_PLUS);
//        this.agility     = getAttribute(soldier.agility, ConfigFactory.ATTRIBUTE_MAGIC_DEF, ConfigFactory.ATTRIBUTE_MAGIC_DEF_PLUS);
//        this.wisdom      = getAttribute(soldier.wisdom, ConfigFactory.ATTRIBUTE_MAGIC_DEF, ConfigFactory.ATTRIBUTE_MAGIC_DEF_PLUS);
        this.fc          = fc;

        this.defaultSkill = new BattleSkill(spriteController, this, soldier.defaultSkill);
        this.cdSkills = new BattleSkill[soldier.cdSkills.length];
        for(int i = 0; i < cdSkills.length; i++)
        {
            cdSkills[i] = new BattleSkill(spriteController, this, soldier.cdSkills[i]);
        }
    }

    private int getAttribute(int base, int attrId, int attrPlusId)
    {
        if(spriteController instanceof PlayerController)
        {
            Sprite player = ((PlayerController) spriteController).getPlayer();
            return (int) (player.getAttribute(attrId) + base * (double)(1 + player.getAttributePlus(attrPlusId)/100));
        }
        else
        {
            return base;
        }
    }

    public void initRoute(List<Position> list)
    {
        this.routeList = list;
        curRouteIndex = 0;
        this.position = routeList.get(0);
        this.status = E_BattleAObjectStatus.GOING;
    }

    @Override
    public boolean isRestrict(BattleAObject target)
    {
        if(target instanceof BattleSoldierAObject)
            return soldier.isRestrict(((BattleSoldierAObject) target).soldier);

        return false;
    }


    @Override
    public void addHP(int value)
    {
        super.addHP(value);

        if(isDie())
        {
            checkDieSkill();

            spriteController.getAttachment().removeSoldier(this);

            battleParentController.removeBattleSoldier(this);
        }
    }

    /**
     * 前进
     */
    @Override
    public void go()
    {
        if(status == E_BattleAObjectStatus.BATTLING)
            return;

        if(routeList == null)
        {
            setStatus(E_BattleAObjectStatus.FREE);
            return;
        }

        if(curRouteIndex >= routeList.size()-1)
        {
            setStatus(E_BattleAObjectStatus.FREE);
            return;
        }

        curRouteIndex++;

        position = routeList.get(curRouteIndex);

        logger.info("BattleSoldierAObject go teamNo:" + teamNo + " uniqueId:" + id + " soldierId:" + soldier.getId() + " name:" + soldier.getName() + " position:" + position + "  总的路线:" + routeList.size() + "  最后的点:" + routeList.get(routeList.size()-1));
    }

    @Override
    public boolean checkCanAtk(BattleAObject target)
    {
        if(target == null)
             return false;

        if(target instanceof BattleSoldierAObject)
        {
            if(!soldier.defaultSkill.checkUnitType(target))
                return false;
        }

        return soldier.defaultSkill.isInAtkRange(this, target);
    }


    @Override
    public TwoTuple<List<BattleAObject>, BattleAObject> checkAtkTarget(List<BattleAObject> targetList)
    {
        BattleAObject atkTarget = null, visionTarget = null;
        List<BattleAObject> result = new CopyOnWriteArrayList<>();
        for(BattleAObject battleAObject : targetList)
        {
            if(atkTarget != null && visionTarget != null && defaultSkill.isSingleTarget())
                break;

            if(!defaultSkill.checkUnitType(battleAObject))
                continue;

            if(atkTarget == null)
            {
                atkTarget = defaultSkill.isInAtkRange(this, battleAObject) ? battleAObject : null;
                if(atkTarget != null)
                {
                    result.add(atkTarget);
                }
            }
            if(visionTarget == null)
            {
                visionTarget = Utils.isInCircleRange(position, battleAObject.getPosition(), soldier.vision) ? battleAObject : null;
            }
        }

        return new TwoTuple<>(result, visionTarget);
    }

//    @Override
//    public boolean checkDefaultSkillCurAtkTargetOK(long currentTime)
//    {
//        if(!defaultSkill.isHaveTarget())
//            return false;
//
//        BattleAObject atkTarget = defaultSkill.getFirstTarget();
//        if(atkTarget == null)
//            return false;
//
//        //是否还在攻击范围内
//        if(!soldier.defaultSkill.isInAtkRange(this, atkTarget))
//        {
//            //不在攻击范围内，要追击，要告诉路线服务器重新获取路线(现在是客户端来当路线服务器的)
//            this.status = E_BattleAObjectStatus.CHASING;
//            //发送获取追击路线指令
//            checkRoute(atkTarget);
//            return false;
//        }
//        else
//        {
//            if(defaultSkill.isCanRelease(currentTime))
//            {
//                //告诉客户端攻击了
//                defaultSkill.release(defaultSkill.getTargets(), atkTarget.getPosition(), currentTime);
//
//                checkDefaultAtk();
//            }
//        }
//
//        return true;
//    }


    @Override
    public void checkDefaultSkillTarget(long currentTime)
    {
        if(checkCDSkill(currentTime))
            return;

        if(!defaultSkill.isCheckTarget())
            return;

        if(!defaultSkill.isCanRelease(currentTime))
            return;

        checkDefaultAtk();

        if(!defaultSkill.isHaveTarget())
        {
            //检测对方主将是否可打
            BattleAObject masterAObject = spriteController.getAttachment().getTargetBattleTmp().getMasterSoldier();
            if(checkCanAtk(masterAObject))
            {
                logger.info(this + " 攻打对方主将:" + masterAObject);
                //打主将
//                addAtkTarget(masterAObject);
                addDefaultAtk(masterAObject);

                battleParentController.sendSoldierBattleStart(this, masterAObject);

                defaultSkill.release(defaultSkill.getTargets(), masterAObject.getPosition(), currentTime);

                checkDefaultAtk();
            }
            else
            {
                TwoTuple<List<BattleAObject>,BattleAObject> targets = checkAtkTarget(spriteController.getAttachment().getTargetBattleTmp().getSoldierList());
                if(targets.getSecond() == null && (targets.getFirst() == null || targets.getFirst().size() == 0))
                {
                    defaultSkill.clearAtkTarget();

//                    logger.info("队伍1 AI向敌方主将寻路:");
                    checkRoute(spriteController.getAttachment().getTargetBattleTmp().getMasterSoldier());
                }
                else if(targets.getFirst() != null && targets.getFirst().size() > 0)
                {
                    logger.info(soldier.getId() + " 检测到攻击目标:" + targets.getFirst() + "  " +targets.getSecond());
                    //找到可以直接攻击的目标，告诉客户端开始攻击
                    addDefaultAtk(targets.getFirst());

                    battleParentController.sendSoldierBattleStart(this, targets.getFirst().get(0));

                    defaultSkill.release(defaultSkill.getTargets(), targets.getFirst().get(0).getPosition(), currentTime);

                    checkDefaultAtk();
                }
                else if(targets.getSecond() != null)
                {
                    //检测是否有在视野范围内有
//                logger.info(soldier.getName() + " 的视野范围内有目标:" + targets.getSecond().getName());
                    //向目标走去，跟路线服务器请求路线
                    checkRoute(targets.getSecond());
                }
            }
        }
        else
        {
            //是否还在攻击范围内
            BattleAObject firstTarget = defaultSkill.getFirstTarget();
            if(!defaultSkill.isInAtkRange(this, firstTarget))
            {
                //不在攻击范围内，要追击，要告诉路线服务器重新获取路线(现在是客户端来当路线服务器的)
                this.status = E_BattleAObjectStatus.CHASING;
                //发送获取追击路线指令
                checkRoute(firstTarget);
            }
            else
            {
                //告诉客户端攻击了
                defaultSkill.release(defaultSkill.getTargets(), firstTarget.getPosition(), currentTime);

                checkDefaultAtk();
            }
        }
    }

    @Override
    public void checkRoute(BattleAObject target)
    {
        if(isEffectActioning())
            return;

        if(!spriteController.isBattling())
            return;

        if(position.isSame(target.getPosition()))
            return;

        if(isSameGoTarget(target))
            return;

        logger.info("当前寻路目标:" + goTarget+" " + soldier.getName() + " 请求路线....自己位置:" + position + " 目标:" + target);

        SGWarProto.S2C_SoldierRoute.Builder request = SGWarProto.S2C_SoldierRoute.newBuilder();
        request.setUniqueId(id);
        request.setStart(position.parsePos());
        request.setEnd(target.getPosition().parsePos());

        battleParentController.dispatchMsg(SGMainProto.E_MSG_ID.MsgID_War_SoldierRoute_VALUE, request.build().toByteArray());

        goTarget = target;
    }




    @Override
    public int getAtkRange()
    {
        return soldier == null ? -1 : soldier.vision;
    }

    @Override
    public String getName()
    {
        return soldier.name;
    }


    public Soldier getSoldier() {
        return soldier;
    }

    public void setSoldier(Soldier soldier) {
        this.soldier = soldier;
    }

    public List<Position> getRouteList() {
        return routeList;
    }

    public void setRouteList(List<Position> routeList) {
        this.routeList = routeList;
    }

    public int getCurRouteIndex() {
        return curRouteIndex;
    }

    public void setCurRouteIndex(int curRouteIndex) {
        this.curRouteIndex = curRouteIndex;
    }


    @Override
    public String toString() {
        return "BattleSoldierAObject{" +
                "id=" + id +
                ",soldier=" + soldier +
                ",teamNo=" + teamNo +
                ",position=" + position +
                ",status=" + status +
                "} ";
    }
}
